#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

using task_t = std::function<void()>;
class Route
{
public:
    Route() { pthread_mutex_init(&_mutex, nullptr); }

    void CheckList(InetAddr &usr)
    {
        LockGuard guard(&_mutex);
        for (auto &user : _userList)
        {
            if (user == usr)
            {
                LOG(DEBUG, "%s is existed\n", usr.addrStr());
                return;
            }
        }
        LOG(DEBUG, "%s is adding\n", usr);
        _userList.push_back(usr);
    }

    void Offline(InetAddr &usr)
    {
        LockGuard guard(&_mutex);
        for (auto iter = _userList.begin(); iter != _userList.end(); ++iter)
        {
            if (*iter == usr)
            {
                LOG(DEBUG, "%s is offline\n", usr.addrStr().c_str());
                _userList.erase(iter);
                break;
            }
        }
    }

    void ForwardHelper(int sockfd, const std::string &message, InetAddr &usr)
    {
        LockGuard guard(&_mutex);
        std::string sendMessage = "[" + usr.addrStr() + "]# " + message;
        for (auto &user : _userList)
        {
            struct sockaddr_in peer = user.addr();
            LOG(DEBUG, "Forward message to %s, message is %s\n",
                user.addrStr().c_str(), sendMessage.c_str());
            ::sendto(sockfd, sendMessage.c_str(), sendMessage.size(), 0,
                     (const sockaddr *)&peer, sizeof(peer));
        }
    }

    void Forward(int sockfd, const std::string &message, InetAddr &usr)
    {
        // 1、维护userList，确保usr在userList内
        CheckList(usr);

        // 2、检查是否为退出信息
        if (message == "QUIT" || message == "Q")
        {
            Offline(usr);
        }

        // 3、转发消息
        // ForwardHelper(sockfd, message, usr);
        // 线程池
        task_t task = std::bind(&Route::ForwardHelper, this, sockfd,
                                message, usr);
        ThreadPool<task_t>::GetInstance()->Equeue(task);
    }

    ~Route() { pthread_mutex_destroy(&_mutex); }

private:
    std::vector<InetAddr> _userList;
    pthread_mutex_t _mutex;
};